------------------------------------------------------------------------------
--  This file is a part of the GRLIB VHDL IP LIBRARY
--  Copyright (C) 2003 - 2008, Gaisler Research
--  Copyright (C) 2008, 2009, Aeroflex Gaisler
--
--  This program is free software; you can redistribute it and/or modify
--  it under the terms of the GNU General Public License as published by
--  the Free Software Foundation; either version 2 of the License, or
--  (at your option) any later version.
--
--  This program is distributed in the hope that it will be useful,
--  but WITHOUT ANY WARRANTY; without even the implied warranty of
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--  GNU General Public License for more details.
--
--  You should have received a copy of the GNU General Public License
--  along with this program; if not, write to the Free Software
--  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
-----------------------------------------------------------------------------
-- Entity:  pci_mtf
-- File:   pci_mtf.vhd
-- Author:  Jiri Gaisler - Gaisler Research
-- Modified:  Alf Vaerneus - Gaisler Research
-- Description: PCI master and target interface
------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library grlib;
use grlib.amba.all;
use grlib.stdlib.all;
use grlib.devices.all;
library techmap;
use techmap.gencomp.all;
library gaisler;
use gaisler.pci.all;
use gaisler.pcilib.all;
use gaisler.misc.all;

entity pci_mtf is
  generic (
    memtech   : integer := DEFMEMTECH;
    hmstndx   : integer := 0;
    dmamst    : integer := NAHBMST;
    readpref  : integer := 0;
    abits     : integer := 21;
    dmaabits  : integer := 26;
    fifodepth : integer := 3; -- FIFO depth
    device_id : integer := 0; -- PCI device ID
    vendor_id : integer := 0; -- PCI vendor ID
    master    : integer := 1; -- Enable PCI Master
    hslvndx   : integer := 0;
    pindex    : integer := 0;
    paddr     : integer := 0;
    pmask     : integer := 16#fff#;
    haddr     : integer := 16#F00#;
    hmask     : integer := 16#F00#;
    ioaddr    : integer := 16#000#;
    irq       : integer := 0;
    irqmask   : integer := 0;
    nsync     : integer range 1 to 2 := 2;	-- 1 or 2 sync regs between clocks
    oepol     : integer := 0;
    endian    : integer := 0;   -- 0 little, 1 big
    class_code: integer := 16#0B4000#;
    rev       : integer := 0;
    scanen    : integer := 0;
    syncrst   : integer := 0;
    hostrst   : integer := 0);
   port(
      rst       : in std_logic;
      clk       : in std_logic;
      pciclk    : in std_logic;
      pcii      : in  pci_in_type;
      pcio      : out pci_out_type;
      apbi      : in apb_slv_in_type;
      apbo      : out apb_slv_out_type;
      ahbmi     : in  ahb_mst_in_type;
      ahbmo     : out ahb_mst_out_type;
      ahbsi     : in  ahb_slv_in_type;
      ahbso     : out ahb_slv_out_type
);
end;

architecture rtl of pci_mtf is

function byte_twist(di : in std_logic_vector(31 downto 0); enable : in std_logic) return std_logic_vector is
  variable do : std_logic_vector(31 downto 0);
begin
  if enable = '1' then
    for i in 0 to 3 loop
      do(31-i*8 downto 24-i*8) := di(31-(3-i)*8 downto 24-(3-i)*8);
    end loop;
  else
    do := di;
  end if;
  return do; 
end function;

function nr_of_1(di : in integer) return integer is
    variable vec : unsigned(31 downto 0);
    variable ones : integer;
begin
    ones := 0;
    vec := to_unsigned(di,32);
    for i in 0 to 31 loop
        if vec(i) = '1' then
            ones := ones + 1;
        end if;
    end loop;
    return ones;
end function;

constant REVISION : amba_version_type := rev;
constant CSYNC : integer := nsync-1;
constant HADDR_WIDTH : integer := 28;
constant MADDR_WIDTH : integer := abits;
constant DMAMADDR_WIDTH : integer := dmaabits;
constant FIFO_DEPTH : integer := fifodepth;
constant FIFO_FULL : std_logic_vector(FIFO_DEPTH - 2 downto 0) := (others => '1');
constant FIFO_DATA_BITS : integer := 32; -- One valid bit
constant NO_CPU_REGS : integer := 6; -- Number of CPU sync registers (pci->ahb)
constant NO_PCI_REGS : integer := 6; -- Number of PCI sync registers (ahb->pci)
constant HMASK_WIDTH : integer := nr_of_1(hmask);

constant pconfig : apb_config_type := (
    0 => ahb_device_reg ( VENDOR_GAISLER, GAISLER_PCIFBRG, 0, REVISION, irq),
    1 => apb_iobar(paddr, pmask));

constant hconfig : ahb_config_type := (
    0 => ahb_device_reg ( VENDOR_GAISLER, GAISLER_PCIFBRG, 0, REVISION, 0),
    4 => ahb_membar(haddr, '0', '0', hmask),
    5 => ahb_iobar (ioaddr, 16#E00#),
    others => zero32);

type pci_input_type is record
  ad       : std_logic_vector(31 downto 0);
  cbe      : std_logic_vector(3 downto 0);
  frame    : std_logic;
  devsel   : std_logic;
  idsel    : std_logic;
  trdy     : std_logic;
  irdy     : std_logic;
  par      : std_logic;
  stop 	   : std_logic;
  gnt      : std_logic;
  host     : std_logic;
end record;

type pci_fifo_in_type is record
  ren : std_logic;
  raddr : std_logic_vector(FIFO_DEPTH - 1 downto 0);
  wen : std_logic;
  waddr : std_logic_vector(FIFO_DEPTH - 1 downto 0);
  wdata : std_logic_vector(FIFO_DATA_BITS - 1 downto 0);
end record;

type pci_fifo_out_type is record
  rdata : std_logic_vector(FIFO_DATA_BITS - 1 downto 0);
end record;

type fifo_type is record
  side     : std_logic; -- Owner access side. Receiver accesses the other side
  raddr    : std_logic_vector(FIFO_DEPTH - 2 downto 0);
  waddr    : std_logic_vector(FIFO_DEPTH - 2 downto 0);
end record;

type pci_target_state_type is (idle, b_busy, s_data, backoff, turn_ar);
type pci_master_state_type is (idle, addr, m_data, turn_ar, s_tar, dr_bus);
type pci_master_fifo_state_type is (idle, addr, incr, last1, sync, t_retry, ttermwd, ttermnd, abort, done, wdone);

type pci_target_type is record
  state    : pci_target_state_type;
  cnt      : std_logic_vector(2 downto 0);
  csel     : std_logic; -- Configuration chip select
  msel     : std_logic; -- Memory hit
  barsel   : std_logic; -- Memory hit
  psel     : std_logic; -- Page hit
  addr     : std_logic_vector(31 downto 0);
  laddr    : std_logic_vector(31 downto 0);
  lsize    : std_logic_vector(1 downto 0);
  lcbe     : std_logic_vector(3 downto 0);
  lwrite   : std_logic;
  lburst   : std_logic;
  lmult    : std_logic;
  mult     : std_logic;
  read     : std_logic; -- PCI target read
  burst    : std_logic;
  pending  : std_logic;
  wdel     : std_logic;
  last     : std_logic;
  fifo     : fifo_type;
  trdy_del : std_logic; -- (delay trdy to send last word in fifo) bug fix *** 
  thold    : std_logic; -- hold target while last word is transfered
  thold2   : std_logic; -- hold target while last word is transfered
  ready_del: std_logic; -- delayed ready
end record;

type pci_master_type is record
  state    : pci_master_state_type;
  fstate   : pci_master_fifo_state_type;
  cnt      : std_logic_vector(2 downto 0);
  ltim     : std_logic_vector(7 downto 0); -- Latency timer
  request  : std_logic;
  hwrite   : std_logic;
  stop_req : std_logic;
  last     : std_logic;
  valid    : std_logic;
  split    : std_logic;
  first    : std_logic;
  firstw   : std_logic;
  fifo     : fifo_type;
  rmdone   : std_logic; -- bug fix ***
  stopframe: std_logic;
  lto      : std_logic; -- bug fix latency timer timeout
end record;

type pci_sync_regs is array (0 to NO_PCI_REGS - 1) of std_logic_vector(csync downto 0);

type pci_reg_type is record
  pci       : pci_sigs_type;
  noe_par   : std_logic;
  noe_ad    : std_logic;
  noe_ctrl  : std_logic;
  noe_cbe   : std_logic;
  noe_frame : std_logic;
  noe_irdy  : std_logic;
  noe_req   : std_logic;
  noe_perr  : std_logic;
  noe_serr  : std_logic;
  m         : pci_master_type;
  t         : pci_target_type;
  comm      : pci_config_command_type; -- Command register
  stat      : pci_config_status_type; -- Status register
  bar0      : std_logic_vector(31 downto MADDR_WIDTH); -- Base Address register 0
  bar1      : std_logic_vector(31 downto DMAMADDR_WIDTH); -- Base Address register 1
  bar0_conf : std_logic;
  bar1_conf : std_logic;
  page      : std_logic_vector(31 downto MADDR_WIDTH-1); -- AHB page
  bt_enable : std_logic;                    -- Byte twist enable, page0 bit 0
  ltim      : std_logic_vector(7 downto 0); -- Latency timer
  cline     : std_logic_vector(7 downto 0); -- Cache Line Size
  intline   : std_logic_vector(7 downto 0); -- Interrupt Line
  syncs     : pci_sync_regs;
  trans     : std_logic_vector(NO_CPU_REGS - 1 downto 0);
end record;

type cpu_master_state_type is (idle, cbe_prepare, write, read_w, read, stop);
type cpu_slave_state_type is (idle, w_wait, t_data, r_hold, r_wait, w_done, t_done);

type cpu_master_type is record
  state     : cpu_master_state_type; -- AMBA master state machine
  dmaddr    : std_logic_vector(31 downto 0);
  fifo      : fifo_type;
  cbe_fifo  : fifo_type;
  cur_cbe   : std_logic_vector(3 downto 0);
  cbe_prep_cnt : std_ulogic;
  read_half : std_logic;
  last_side_wr : std_ulogic;
end record;

type cpu_slave_type is record
  state       : cpu_slave_state_type; -- AMBA slave state machine
  maddr       : std_logic_vector(31 downto 0);
  mdata       : std_logic_vector(31 downto 0);
  be          : std_logic_vector(3 downto 0);
  perror      : std_logic;
  hresp       : std_logic_vector(1 downto 0);
  hready      : std_logic;
  htrans      : std_logic_vector(1 downto 0);
  hmaster     : std_logic_vector(3 downto 0); 
  pcicomm     : std_logic_vector(3 downto 0);
  hold        : std_logic;
  fifos_write : std_logic;
  fifo        : fifo_type;
  last_side   : std_logic;
  hold_retry  : std_logic_vector(1 downto 0); -- Used to detect non-burst accesses in r_hold state -- *** 
end record;

type cpu_sync_regs is array (0 to NO_CPU_REGS - 1) of std_logic_vector(csync downto 0);

type cpu_reg_type is record
  m        : cpu_master_type;
  s        : cpu_slave_type;
  syncs    : cpu_sync_regs;
  trans    : std_logic_vector(NO_PCI_REGS - 1 downto 0);
  pciba    : std_logic_vector(HMASK_WIDTH-1 downto 0);
  cfto     : std_logic;
  wcomm    : std_logic;
  rcomm    : std_logic;
  werr     : std_logic;
  clscnt   : std_logic_vector(8 downto 0);
  dmapage  : std_logic_vector(31 downto DMAMADDR_WIDTH); -- DMA page
  ioba     : std_logic_vector(15 downto 0);
  bus_nr   : std_logic_vector(3 downto 0);
  irq      : std_logic_vector(9 downto 0);
  irq_en   : std_logic_vector(9 downto 0);
  pirq     : std_logic_vector(0 to 1);
end record;

signal clk_int : std_logic;
signal pr : pci_input_type;
signal r, rin : pci_reg_type;
signal r2, r2in : cpu_reg_type;
signal dmai : ahb_dma_in_type;
signal dmao : ahb_dma_out_type;
signal fifo1i, fifo2i, fifo3i, fifo4i, cbe_fifoi : pci_fifo_in_type;
signal fifo1o, fifo2o, fifo3o, fifo4o, cbe_fifoo : pci_fifo_out_type;
signal roe_ad, rioe_ad : std_logic_vector(31 downto 0); 
signal pcirst  : std_logic;
signal prrst  : std_logic;
signal pcirstin : std_logic;
attribute sync_set_reset : string;
attribute sync_set_reset of prrst : signal is "true";
attribute async_set_reset : string;
attribute async_set_reset of pcirst : signal is "true";

attribute syn_preserve : boolean;
attribute syn_preserve of roe_ad : signal is true; 
begin

-----------------------------------------------
-- Back-end state machine (AHB clock domain) --
-----------------------------------------------
    
    comb : process (rst, r2, r, dmao, ahbsi, fifo2o, fifo4o, apbi, pr,
                    cbe_fifoo, dmai, pcii)
        
        variable vdmai : ahb_dma_in_type;
        variable v : cpu_reg_type;
        variable hready : std_logic;
        variable hresp, hsize : std_logic_vector(1 downto 0);
        variable p_done, wsdone, wmdone, rtdone, rmdone : std_logic;
        variable pstart, habort, hstart_ack : std_logic;
        variable hstart, pabort, pstart_ack, pcidc : std_logic;
        variable i : integer range 0 to NO_CPU_REGS;
        variable fifom_write, fifos_write : std_logic;
        variable prdata : std_logic_vector(31 downto 0);
        variable wmvalid, wsvalid, rmvalid, rsvalid, burst_read, hold : std_logic;
        variable fifors_limit, fifows_limit,fiform_limit, fifowm_limit, fifows_stop : std_logic;
        variable comp, request, s_read_side, m_read_side : std_logic;
        variable ahb_access : std_logic; -- *** access control fix
        variable start, single_access : std_logic;
        variable next_cbe : std_logic_vector(3 downto 0);
        variable byteaddr : std_logic_vector(1 downto 0);
    begin

        
        v := r2;
        vdmai.start := '0'; 
        vdmai.irq := '0'; vdmai.busy := '0'; vdmai.burst := '1';
        vdmai.wdata := fifo2o.rdata(31 downto 0); vdmai.write := r.t.lwrite;
        rmvalid := '1'; wmvalid := '1'; request := '0'; hold := '0';
        rsvalid := '1'; wsvalid := '1'; burst_read := '0';
        hready := '1'; hresp := HRESP_OKAY; hsize := "10";
        fifom_write := '0'; v.s.fifos_write := '0';
        comp := '0'; prdata := (others => '0'); v.s.hold := '0';
        s_read_side := not r.m.fifo.side; m_read_side := not r.t.fifo.side;
        ahb_access := '0'; -- *** access control fix
       
        -- Synch registers
        pstart     := r2.trans(0);
        habort     := r2.trans(1);
        hstart_ack := r2.trans(2);
--    fifows_limit := r2.trans(3);
        wsdone     := r2.trans(4);
        wmdone     := r2.trans(5);

        for i in 0 to NO_CPU_REGS - 1 loop
            v.syncs(i)(csync) := r.trans(i);
            if csync /= 0 then v.syncs(i)(0) := r2.syncs(i)(csync); end if;
        end loop;

        hstart      := r2.syncs(0)(0);
        pabort      := r2.syncs(1)(0);
        pstart_ack  := r2.syncs(2)(0);
        pcidc       := r2.syncs(3)(0);
        rtdone      := r2.syncs(4)(0);
        rmdone      := r2.syncs(5)(0);
        
        p_done := pstart_ack or pabort;

        -- Interrupts
        if irq /= 0 then
            if to_x01(pcii.host) = '0' then
                v.irq(3 downto 0) := (not pcii.int);
            end if;
        end if;
        v.irq(9 downto 4) := r.stat.dpe & r.stat.sse & r.stat.rma & r.stat.rta & r.stat.sta & r.stat.dped;
        apbo.pirq <= (others => '0');
        apbo.pirq(irq) <= orv(r2.irq and r2.irq_en);

        if r2.m.fifo.raddr = FIFO_FULL then fiform_limit := '1'; else fiform_limit := '0'; end if;
        if r2.m.fifo.waddr = FIFO_FULL then fifowm_limit := '1'; else fifowm_limit := '0'; end if;
        if r2.s.fifo.raddr = FIFO_FULL then fifors_limit := '1'; else fifors_limit := '0'; end if;
        if r2.s.fifo.waddr = FIFO_FULL then fifows_limit := '1'; else fifows_limit := '0'; end if;
        if r2.s.fifo.waddr(FIFO_DEPTH - 2 downto 1) = FIFO_FULL(FIFO_DEPTH - 2 downto 1) then fifows_stop := '1'; else fifows_stop := '0'; end if;

-----------------------------------
---- APB Control & Status regs ----
-----------------------------------
        
        if (apbi.psel(pindex) and apbi.penable) = '1' then
            case apbi.paddr(4 downto 2) is
                when "000" =>
                    if apbi.pwrite = '1' then
                        v.pciba := apbi.pwdata(31 downto 31-HMASK_WIDTH+1);
                        v.bus_nr := apbi.pwdata(26 downto 23);
                        v.werr := r2.werr and not apbi.pwdata(14);
                        v.wcomm := apbi.pwdata(10) and r.comm.mwie;
                        v.rcomm := apbi.pwdata(9);
                    end if;
                    prdata(31 downto 31-HMASK_WIDTH+1) := r2.pciba;
                    prdata(26 downto 23) := r2.bus_nr;
                    prdata(22 downto 0) := r.ltim & r2.werr & not pr.host & r.comm.msen & r.comm.men & r2.wcomm & r2.rcomm & r2.cfto & r.cline;
                when "001" =>
                    prdata := r.bar0(31 downto MADDR_WIDTH) & addzero(MADDR_WIDTH-1 downto 0);
                when "010" =>
                    prdata := r.page(31 downto MADDR_WIDTH-1) & addzero(MADDR_WIDTH-2 downto 1) & r.bt_enable;
                when "011" =>
                    prdata := r.bar1(31 downto DMAMADDR_WIDTH) & addzero(DMAMADDR_WIDTH-1 downto 0);
                when "100" =>
                    if apbi.pwrite = '1' then
                        v.dmapage(31 downto DMAMADDR_WIDTH) := apbi.pwdata(31 downto DMAMADDR_WIDTH);
                    end if;
                    prdata := r2.dmapage(31 downto DMAMADDR_WIDTH) & addzero(DMAMADDR_WIDTH-1 downto 0);
                when "101" =>
                    if apbi.pwrite = '1' then
                        v.ioba := apbi.pwdata(31 downto 16);
                    end if;
                    prdata := r2.ioba & addzero(15 downto 4) & hstart & hstart_ack & pstart & pstart_ack;
                when "110" =>
                    prdata(1)  := r.comm.men;
                    prdata(2)  := r.comm.msen;
                    prdata(4)  := r.comm.mwie;
                    prdata(6)  := r.comm.per;
                    prdata(8)  := r.comm.ser;
                    prdata(24) := r.stat.dped;
                    prdata(26) := '1';
                    prdata(27) := r.stat.sta;
                    prdata(28) := r.stat.rta;
                    prdata(29) := r.stat.rma;
                    prdata(30) := r.stat.sse;
                    prdata(31) := r.stat.dpe;
                when "111" =>
                     if apbi.pwrite = '1' then
                        v.irq_en := apbi.pwdata(25 downto 16);
                     end if;
                     prdata(31 downto 26) := (others => '0');
                     prdata(25 downto 16) := r2.irq_en;
                     prdata(15 downto 10) := (others => '0');
                     prdata(9 downto 0)   := r2.irq;
                when others =>
            end case;
        end if;
        
---------------------
---- AHB MASTER  ----
---------------------
        
        -- Burst control
        if (r2.m.state = read or r2.m.state = read_w) then
            if r.t.lmult = '1' then
                comp := fifowm_limit and r2.m.fifo.side;
            elsif r.t.lburst = '1' then
                if r2.clscnt(8) = '1' then comp := '1';
                else v.clscnt := r2.clscnt - (dmao.active and dmao.ready); end if;
            else comp := '1'; end if;
        else
            v.clscnt := '0' & (r.cline - '1'); -- set burst counter to cache line size
        end if;
     
        if (rtdone = '1' and (r2.m.fifo.raddr + '1') = r.t.fifo.waddr) then rmvalid := '0'; end if;

        -- step DMA address
        if dmao.ready = '1' then
            v.m.dmaddr(31 downto 2) := r2.m.dmaddr(31 downto 2) + '1';
        end if;

        -- Translate current CBE to hsize and address
        byteaddr := "00";        
        if endian = 0 then -- pci is little endian
            case r2.m.cur_cbe is
                when "0000" =>       -- 32 bit access
                    vdmai.size := "10";  byteaddr  := "00";
                when "1100" =>       -- 16 bit 
                    vdmai.size := "01";  byteaddr  := "00";
                when "0011" =>
                    vdmai.size := "01";  byteaddr  := "10";
                when "1110" =>       -- 8 bit
                    vdmai.size := "00";  byteaddr  := "00";
                when "1101" =>
                    vdmai.size := "00";  byteaddr  := "01";
                when "1011" =>
                    vdmai.size := "00";  byteaddr  := "10";
                when "0111" =>
                    vdmai.size := "00";  byteaddr  := "11";
                when others => vdmai.size := "10";
            end case;
        else -- big endian
            case  r2.m.cur_cbe is
                when "0000" =>       -- 32 bit access
                    vdmai.size := "10";  byteaddr  := "00";
                when "0011" =>       -- 16 bit 
                    vdmai.size := "01";  byteaddr  := "00";
                when "1100" =>
                    vdmai.size := "01";  byteaddr  := "10";
                when "0111" =>       -- 8 bit
                    vdmai.size := "00";  byteaddr  := "00";
                when "1011" =>
                    vdmai.size := "00";  byteaddr  := "01";
                when "1101" =>
                    vdmai.size := "00";  byteaddr  := "10";
                when "1110" =>
                    vdmai.size := "00";  byteaddr  := "11";
                when others => vdmai.size := "10";
            end case;
        end if;

        vdmai.address := r2.m.dmaddr(31 downto 2) & byteaddr;
        next_cbe := cbe_fifoo.rdata(3 downto 0);
        
        -- AHB master state machine
        case r2.m.state is
            
            when idle =>
                v.m.read_half := '0';
                v.m.last_side_wr := '0';
                v.m.cur_cbe := (others => '0');
                v.m.fifo.waddr := (others => '0');

                if hstart = '1' then
                    
                    wmdone         := '0';
                    fifowm_limit   := '0';
--                    v.m.fifo.waddr := (others => '0');
                                        
                    if r.t.lwrite = '1'  then

                        v.m.dmaddr := r.t.laddr;
                        v.m.state := write;
                        v.m.cur_cbe := cbe_fifoo.rdata(3 downto 0);

                        -- burst access
                        if rtdone = '0' or conv_integer(r.t.fifo.waddr) /= 1 then
                            v.m.cbe_fifo.raddr := r2.m.cbe_fifo.raddr + 1;
                            v.m.state := cbe_prepare;
                            v.m.cbe_prep_cnt := '1';
                        end if;

--                      vdmai.busy := '1';
--                      if rmvalid = '1' then v.m.state := write;
--                      else vdmai.start := '0'; v.m.state := stop; end if;
                        
                    else
                        --vdmai.start := '1';
                        v.m.state := read_w;
                        v.m.dmaddr := r.t.laddr;
                    end if;
                    
                -- Latching dmaddr is now only done when hstart = 1 [nisse]
                else --v.m.dmaddr := r.t.laddr; 
                end if;

            when cbe_prepare =>
                v.m.cur_cbe := next_cbe;

                -- Need to wait for correct cycle to sample next
                -- cbe if we have switched FIFO side.
                if r2.m.cbe_prep_cnt = '1' then
                    v.m.state := write;
                else
                    v.m.cbe_prep_cnt := '1';
                end if;
                
            when write =>

                start := '0';

                --if fiform_limit = '1' then
                --if fiform_limit = '1' and dmao.start = '1' then  -- 1k bug fix (store last word in first 
                --    v.m.read_half := '1';                        --             fifo half if addr = 0x400 ...)
                --end if;
                --if fiform_limit = '1' and dmao.start = '1' and dmao.ready = '1' then  -- 1k bug fix (store last word in first 
                -- Need to check dmao active and ready to handle retry/split on last word (check dmao start instead of active result in lockup if waitstates on AHB)
                if fiform_limit = '1' and dmao.active = '1' and dmao.ready = '1' then  -- 1k bug fix (store last word in first 
                    v.m.read_half := '1';                        --             fifo half if addr = 0x400 ...)
                end if;
                
                -- Don't start again until PCI side is done filling second half of fifo (bug fix kc)
                if r2.m.read_half = '1' then
                    if rtdone = '1' then
                        start := ((rmvalid and not fiform_limit) or (not dmao.active and not rmvalid));
                    end if;
                else
--                  vdmai.start := ((rmvalid and not fiform_limit) or (not dmao.active and not rmvalid));
                    -- 1k bug fix (store last word in first fifo half if addr = 0x400 ...)

                    start := ((rmvalid and not v.m.read_half) or (not dmao.active and not rmvalid));
                end if;
                                
                -- Burst CBE handling
                if rtdone = '0' or conv_integer(r.t.fifo.waddr) /= 1 then 

                    -- Current or access is subword. Must be forced to single access
                    if r2.m.cur_cbe /= "0000" then
                        
                        vdmai.burst := '0';
                        
                        if dmao.active = '1' then
                            start := '0';
                        end if;
                            
                    end if;

                    -- Next access is subword. Make current access last in burst
                    if rmvalid = '1' and next_cbe /= "0000" then
                        
                        if dmao.active = '1' then
                            start := '0';
                        end if;
                            
                    end if;
                    
                end if;

                vdmai.start := start;

                -- End of data phase for access with cur_cbe
                if (dmao.active and dmao.ready) = '1' then

                    v.m.fifo.raddr     := r2.m.fifo.raddr     + (rmvalid and not fiform_limit and not dmao.mexc);
                    v.m.cbe_fifo.raddr := r2.m.cbe_fifo.raddr + (rmvalid and not fiform_limit and not dmao.mexc);

                    v.m.last_side_wr := m_read_side;
                    
                    -- First half of FIFO
                    if v.m.read_half = '0' then
                        v.m.cur_cbe := next_cbe;
                        
                    -- FIFO side switch
                    elsif r2.m.read_half = '0' then
                        v.m.cbe_prep_cnt := '0';
                        v.m.state := cbe_prepare;

                    elsif v.m.last_side_wr = '0' then
                        v.m.cbe_prep_cnt := '0';
                        v.m.state := cbe_prepare;
                        
                    -- Second side of FIFO
                    else
                        v.m.cur_cbe := next_cbe;
                    end if;

                    if (dmao.mexc = '1' or rmvalid = '0') then
                        habort := dmao.mexc and not r.t.lwrite;
                        v.werr := r2.werr or (dmao.mexc and r.t.lwrite);
                        v.m.state := stop;
                    end if;
                end if;
                
            when read_w =>
                
                vdmai.start := not (comp and dmao.active);

                if dmao.mexc = '1' then
                    habort := not r.t.lwrite;
                    v.werr := '1';
                    v.m.state := stop;
                    
                elsif dmao.ready = '1' then
                    fifom_write := '1';
                    wmvalid := not (comp or dmao.mexc);
                    if comp = '1' then
                        v.m.state := stop;
                        v.m.fifo.waddr := r2.m.fifo.waddr + '1';
                        
                    else
                        v.m.fifo.waddr := r2.m.fifo.waddr + (not fifowm_limit);
                        v.m.state := read; end if;
                end if;
                
            when read =>
                
                vdmai.start := not (comp and dmao.active);
                fifom_write := dmao.ready; wmvalid := not (comp or dmao.mexc);
--      if ((comp and dmao.ready) or dmao.retry) = '1' then
                if (comp and dmao.ready) = '1' then
                    v.m.state := stop; v.m.fifo.waddr := r2.m.fifo.waddr + '1';
                elsif (dmao.active and dmao.ready) = '1' then
                    v.m.fifo.waddr := r2.m.fifo.waddr + (not dmao.mexc and not fifowm_limit);
                    if dmao.mexc = '1' then habort := not r.t.lwrite; v.werr := r2.werr or r.t.lwrite; v.m.state := stop; end if;
                end if;
                
            when stop =>
                
                if hstart = '0' and ((r.t.lwrite and not fiform_limit) = '1' or wmdone = '1') then
                    v.m.state := idle; hstart_ack := '0';
                    v.m.fifo.side := '0'; habort := '0';

                    v.m.fifo.raddr := (others => '0');
                    v.m.cbe_fifo.raddr := (others => '0');
                else
                    comp := '1';
                    fiform_limit := r.t.lwrite;
                    fifowm_limit := not r.t.lwrite;
                end if;
        end case;

        -- FIFO control
        if fifowm_limit = '1' then
--      if (((r2.m.fifo.side or hstart_ack or (not hstart)) = '0' and not (dmao.active and not dmao.ready) = '1')
            if (((r2.m.fifo.side or hstart_ack or (not hstart)) = '0' and (dmao.ready or comp) = '1')
                or ((hstart_ack and not hstart) = '1' and v.m.state = stop)) then
                if v.m.state = stop then wmdone := '1';
                else v.m.fifo.waddr := (others => '0'); end if;
                hstart_ack := '1';
                v.m.fifo.side := not r2.m.fifo.side;
            end if;
        elsif fiform_limit = '1' then
--      if dmao.active = '0' then
            if dmao.active = '0' and dmai.start = '0' then -- 1k bug fix ***
                m_read_side := '1';
                hstart_ack := '1';
--        v.m.fifo.raddr := (others => hstart);

                v.m.fifo.raddr := (others => '0'); -- 1k bug fix ***
                v.m.cbe_fifo.raddr := conv_std_logic_vector(1, FIFO_DEPTH-1);
                
            end if;
        end if;

-----------------------        
--- AHB MASTER END ----
-----------------------

        
-------------------
---- AHB SLAVE ----
-------------------
        
--    if MASTER = 1 then

        -- Access decode
        if (ahbsi.hready and ahbsi.hsel(hslvndx)) = '1' then
            if (ahbsi.hmbsel(0) or ahbsi.hmbsel(1)) = '1' then
                hsize := ahbsi.hsize(1 downto 0); v.s.htrans := ahbsi.htrans;
                --if (v.s.htrans(1) and r.comm.msen) = '1' then request := '1'; end if;
                if (v.s.htrans(1) and r.comm.msen) = '1' then -- fix access control ***
                    ahb_access := '1';
                    --if (r2.s.state /= r_wait and r2.s.state /= r_hold) or r2.s.hmaster = ahbsi.hmaster then
                    --if (r2.s.state = idle or r2.s.state = t_done) or r2.s.hmaster = ahbsi.hmaster then
                    if (r2.s.state = idle) or r2.s.hmaster = ahbsi.hmaster then
                        request := '1';
                    end if;
                end if;
            end if;
        end if;

        -- Access latches
        if (request = '1' and r2.s.state = idle) then
            
            if ahbsi.hmbsel(1)  = '1' then
                if ahbsi.haddr(16) = '1' then -- Configuration cycles

                    v.s.maddr := (others => '0');
                    
                    if r2.bus_nr = "0000" then -- Type 0
                        
                        v.s.maddr(conv_integer(ahbsi.haddr(15 downto 11)) + 10) := '1';
                        v.s.maddr(10 downto 0) := ahbsi.haddr(10 downto 2) & "00";

                    else -- Type 1

                        v.s.maddr(19 downto 0) := r2.bus_nr & ahbsi.haddr(15 downto 2) & "01";

                    end if;

                    v.s.pcicomm := "101" & ahbsi.hwrite;
                    
                else -- I/O space access
                    
                    v.s.maddr(31 downto 16) := r2.ioba;
                    v.s.maddr(15 downto 0) := ahbsi.haddr(15 downto 0);
                    v.s.pcicomm := "001" & ahbsi.hwrite;
                    
                end if;
                
            else -- Memory space access
                
                if conv_integer(ahbsi.hmaster) = dmamst then
                    v.s.maddr := ahbsi.haddr;
                else
                    v.s.maddr := r2.pciba & ahbsi.haddr(31-HMASK_WIDTH downto 2) & "00";
                end if;
                
                if ahbsi.hwrite = '1' then
                    v.s.pcicomm := r2.wcomm & "111";
                else
                    v.s.pcicomm := ahbsi.hburst(0) & '1' & (r2.rcomm or not ahbsi.hburst(0)) & '0';
                end if;
                
            end if;

            -- Decode HSIZE and HADDR
            if endian = 0 then -- pci is little endian
                
                case hsize is
                    when "00" => -- Decode byte enable
                        case ahbsi.haddr(1 downto 0) is
                            when "00" => v.s.be := "1110";
                            when "01" => v.s.be := "1101";
                            when "10" => v.s.be := "1011";
                            when "11" => v.s.be := "0111";
                            when others => v.s.be := "1111";
                        end case;
                    when "01" =>
                        case ahbsi.haddr(1 downto 0) is
                            when "00" =>   v.s.be := "1100";
                            when "10" =>   v.s.be := "0011";
                            when others => v.s.be := "1111";
                        end case;
                    when  "10" => v.s.be := "0000";
                    when others => v.s.be := "1111";
                end case;
                
            else     -- pci is big endian
                
                case hsize is
                    when "00" => -- Decode byte enable
                        case ahbsi.haddr(1 downto 0) is
                            when "00" => v.s.be   := "0111";
                            when "01" => v.s.be   := "1011";
                            when "10" => v.s.be   := "1101";
                            when "11" => v.s.be   := "1110";
                            when others => v.s.be := "1111";
                        end case;
                    when "01" =>
                        case ahbsi.haddr(1 downto 0) is
                            when "00" =>   v.s.be := "0011";
                            when "10" =>   v.s.be := "1100";
                            when others => v.s.be := "1111";
                        end case;
                    when  "10" => v.s.be := "0000";
                    when others => v.s.be := "1111";
                end case;

            end if;

        end if;

        if ((rmdone and not r2.s.pcicomm(0)) = '1' and (r2.s.fifo.raddr + '1' + pcidc) = r.m.fifo.waddr) then rsvalid := '0'; end if;

        -- FIFO address counters
--      if (r2.s.state = t_data or r2.s.state = w_wait) then
        if (r2.s.state = t_data or r2.s.state = w_wait or  -- bug fix ***
            --(r2.s.state = r_hold and fifors_limit = '0' and ((pstart_ack or pstart) = '0') and request = '1')) then -- (r_hold -> t_data) bug fix ***
            (r2.s.state = r_hold and fifors_limit = '0' and ((pstart_ack or pstart) = '0') and request = '1' and rmdone = '1')) then -- (r_hold -> t_data) bug fix ***
            v.s.fifos_write := r2.s.pcicomm(0) and r2.s.htrans(1);
            v.s.fifo.waddr := r2.s.fifo.waddr + r2.s.fifos_write;
            v.s.fifo.raddr := r2.s.fifo.raddr + ((ahbsi.htrans(1) and not r2.s.pcicomm(0) and not fifors_limit and rsvalid) or not ahbsi.hready);

        end if;

        if pstart_ack = '1' then
            if pabort = '1' then
                if (r2.s.pcicomm = CONF_WRITE or r2.s.pcicomm = CONF_READ) then v.cfto := '1';
                else v.s.perror := '1'; end if;
            else v.s.perror := '0'; v.cfto := '0'; end if;
        end if;
        
        --

        
        -- AHB slave state machine
        case r2.s.state is
            
            when idle =>
                v.s.hold_retry := "00"; 
                
                if request = '1' and p_done = '0' then
                    if ahbsi.hwrite = '1' then
                        v.s.state := w_wait;
                        v.s.fifo.side := '0';
                    else
                        pstart := '1'; v.s.state := r_wait;
                    end if;
                    v.s.hmaster := ahbsi.hmaster; 
                end if;
                
            when w_wait =>
                
                if ((ahbsi.hready and not ahbsi.htrans(0)) = '1') then
                    v.s.state := w_done; fifows_limit := not wsvalid;
                else
                    v.s.state := t_data;
                end if;
                
            when t_data =>
                if ahbsi.htrans(1) = '1' then v.s.hold_retry := "00"; end if;
                burst_read := ahbsi.htrans(1) and not fifors_limit;
                
                if (fifows_stop and r2.s.fifos_write) = '1' then
                    if r2.s.fifo.side = '1' then
                        v.s.state := w_done;
                    end if;
                    
                elsif ((fifors_limit or not rsvalid) = '1' and v.s.htrans(1) = '1') then
                    if (r.m.fifo.side = '0') or (rsvalid = '0') then
                        v.s.state := t_done;
                    --else v.s.state := r_hold; end if;
                    else v.s.state := r_hold; v.s.hold_retry := "00"; end if;  -- reset hold_retry ***
                end if;
                
                if ((ahbsi.hready and not ahbsi.htrans(0)) = '1') then
                    if r2.s.pcicomm(0) = '1' then
                        --v.s.state := w_done; wsvalid := '0';
                        v.s.state := w_done; 
                        if ahbsi.htrans /= "00" then wsvalid := '0'; end if; -- fix dont set wsvalid if amba idle
                    else                                                   -- (if wsvalid = 0 side is changed before last write 
                        v.s.state := t_done;                                 -- to fifo if hrans = 00)        
                        wsvalid := '0'; -- Bug fix, must give RETRY here! /KC
                    end if;
                end if;
                
            when r_hold =>
                
                s_read_side := '1';

                if r2.s.hold_retry(1) = '0' then -- only check this once (first access)
                  if ahbsi.htrans = "11" then
                    v.s.hold_retry := "11"; -- Seq Burst access 
                  elsif ahbsi.htrans /= "01" then -- if busy, wait to decide
                    v.s.hold_retry := "10"; -- New nonseq or idle
                  end if;
                end if;
                
                if v.s.hold_retry = "10" then 
                  v.s.state := t_done;
                --elsif fifors_limit = '0' and ((pstart_ack or pstart) = '0') and request = '1' and v.s.hold_retry = "11" then
                elsif rmdone = '1' and fifors_limit = '0' and ((pstart_ack or pstart) = '0') and request = '1' and v.s.hold_retry = "11" then
                  v.s.state := t_data;
                  burst_read := ahbsi.htrans(1) and not fifors_limit; -- bug fix ***
                else
                  v.s.hold := '1';
                end if;

                --if fifors_limit = '0' and ((pstart_ack or pstart) = '0') and request = '1' then
                --    --if rmdone = '0' then -- bug fix *** 
                --        v.s.state := t_data;
                --        burst_read := ahbsi.htrans(1) and not fifors_limit; -- bug fix ***
                --    --else
                --    --    v.s.state := t_done;  
                --    --end if;
                --elsif (ahbsi.hready = '1' and ahbsi.htrans = "00" and r2.s.hresp = HRESP_OKAY) then -- (idle -> t_done) bug fix *** 
                --    v.s.state := t_done;
                --else v.s.hold := '1'; end if;
            when r_wait =>
                
                s_read_side := '0';
                if (pstart_ack and request) = '1' then
                    v.s.state := t_data; hready := '0';
                end if;

                if r2.s.hmaster /= ahbsi.hmaster and conv_integer(ahbsi.hmaster) = dmamst and pstart_ack = '1' then -- if pcidma cancel read  
                    v.s.state := t_done;
                end if;

            when w_done =>
                
                v.s.state := t_done; wsvalid := '0';
--        if (r2.s.htrans(1) or not fifows_limit) = '1' then
--        if (r2.s.htrans(1) and fifows_limit) = '1' then
                v.s.fifo.waddr := r2.s.fifo.waddr + r2.s.fifos_write;

                
--          end if;

                fifows_limit := '1'; 
            when t_done =>
                
                wsvalid := '0';
                fifors_limit := not r2.s.pcicomm(0);
                if (pstart or pstart_ack) = '0' then
                    v.s.state := idle; v.s.perror := '0';
                    v.s.fifo.waddr := (others => '0'); wsdone := '0'; fifows_limit := '0';
                    v.s.pcicomm := (0 => '1', others => '0'); -- default write
                else fifows_limit := r2.s.pcicomm(0); end if;
        end case;

        -- Respond encoder
        if v.s.state = t_data
            or (v.s.state = r_hold and v.s.hold = '0') -- bug fix ***
            or (v.s.state = t_done and r2.s.state = t_data) -- (end of trans) bug fix ***
            or (v.s.state = w_wait and ahbsi.hwrite = '1') then
            if r2.s.perror = '1' then hresp := HRESP_ERROR;
            elsif wsvalid = '1' then hresp := HRESP_OKAY;
            else hresp := HRESP_RETRY; end if;
            v.s.perror := '0';
        else hresp := HRESP_RETRY; end if;
        
        -- added to provent read from unvalid fifo address
        if r2.s.state = t_data and rsvalid = '0' and r2.s.hold_retry /= "00" then hresp := HRESP_RETRY; end if;

        if r.comm.msen = '0' then hresp := HRESP_ERROR; end if; -- Master disabled
        --if (v.s.htrans(1) and request) = '0' then hresp := HRESP_OKAY; end if; -- Response OK for BUSY and IDLE
        if (v.s.htrans(1) and ahb_access) = '0' then hresp := HRESP_OKAY; end if; -- Response OK for BUSY and IDLE -- *** access control fix
        if (hresp /= HRESP_OKAY or hready = '0') then v.s.hready := '0'; else v.s.hready := '1'; end if;

        -- Dont change hresp during wait states
        if ahbsi.hready = '0' then hresp := r2.s.hresp; end if;
        v.s.hresp := hresp;

        -- FIFO controller
        if fifows_limit = '1' then
            if (r2.s.fifos_write or not wsvalid) = '1' and (r2.s.fifo.side = '0' or pstart_ack = '1')   then
                --if wsvalid = '0' then wsdone := '1';
                if wsvalid = '0' or v.s.state = w_done then wsdone := '1'; -- fix set wsdone and pstart at the same time
                else v.s.fifo.waddr := (others => '0'); end if;
                pstart := not pstart_ack;
                v.s.fifo.side := pstart;
            end if;
        elsif ((r2.s.state = t_done or r2.s.state = r_hold) and fifors_limit = '1') then
            if pstart_ack = '1' then pstart := '0'; v.s.fifo.raddr := (others => '0');
            else v.s.fifo.raddr := (others => '0'); end if;
        end if;

        -- Set last fifo side written so that PCI master knows when to stop
        if (r2.s.fifos_write = '1') then
            v.s.last_side := r2.s.fifo.side;
        end if;

--    end if;

-----------------------
---- AHB SLAVE END ----
-----------------------
        
        -- Sync registers
        v.trans(0) := pstart;
        v.trans(1) := habort;
        v.trans(2) := hstart_ack;
        v.trans(3) := fifows_limit;
        v.trans(4) := wsdone;
        v.trans(5) := wmdone;

        -- input data for write accesses
        if r2.s.pcicomm(0) = '1' then v.s.mdata := ahbsi.hwdata; end if;
        -- output data for read accesses
--    if (ahbsi.htrans(1) and not r2.s.hold and not r2.s.pcicomm(0)) = '1' then v.s.mdata := fifo4o.rdata(31 downto 0); end if;
        if (ahbsi.htrans(1) and not r2.s.pcicomm(0)) = '1' then v.s.mdata := fifo4o.rdata(31 downto 0); end if; -- bug fix ***
        
        if rst = '0' then
            v.s.state  := idle;
            v.m.state  := idle;
            v.s.perror := '0';
            v.pciba := (others => '0');
            v.trans := (others => '0');
            v.m.cbe_fifo.waddr := (others => '0');
            v.m.cbe_fifo.raddr := (others => '0');
            v.m.fifo.waddr := (others => '0');
            v.m.fifo.raddr := (others => '0');
            v.s.fifo.waddr := (others => '0');
            v.s.fifo.raddr := (others => '0');
            v.m.fifo.side  := '0';
            v.s.fifo.side  := '0';
            v.wcomm   := '0';
            v.rcomm   := '0';
            v.werr    := '0';
            v.cfto    := '0';
            v.dmapage := (others => '0');
            v.ioba    := (others => '0');
            v.bus_nr  := (others => '0');
            v.irq     := (others => '0');
            v.irq_en  := (others => '0');
        end if;

        apbo.prdata  <= prdata;
        ahbso.hready <= r2.s.hready;
        ahbso.hresp  <= r2.s.hresp;
        ahbso.hrdata <= byte_twist(r2.s.mdata, r.bt_enable);
        ahbso.hindex <= hslvndx;

        fifo1i.wen   <= fifom_write;
        fifo1i.waddr <= r2.m.fifo.side & r2.m.fifo.waddr;
        fifo1i.wdata <= dmao.rdata;

        fifo2i.ren   <= '1';
        fifo2i.raddr <= m_read_side & (r2.m.fifo.raddr + dmao.ready);
        
        fifo3i.wen   <= r2.s.fifos_write;
        fifo3i.waddr <= r2.s.fifo.side & r2.s.fifo.waddr;
        fifo3i.wdata <= byte_twist(r2.s.mdata, r.bt_enable);
        
        fifo4i.ren   <= '1';
        fifo4i.raddr <= s_read_side & (r2.s.fifo.raddr + burst_read);

        cbe_fifoi.ren   <= '1';
        cbe_fifoi.raddr <= m_read_side & (r2.m.cbe_fifo.raddr + dmao.ready); -- read one cycle before data fifo

        r2in <= v; dmai <= vdmai;
        
    end process;

    ahbso.hconfig <= hconfig when MASTER = 1 else (others => zero32);
    ahbso.hcache  <= '0';
    apbo.pconfig  <= pconfig;
    apbo.pindex   <= pindex;
    ahbso.hsplit  <= (others => '0');
    ahbso.hirq    <= (others => '0');


---------------------------------
-- PCI core (PCI clock domain) --
---------------------------------
    
    pcicomb : process(pr, pcii, r, r2, fifo1o, fifo3o, roe_ad, prrst, ahbmi,
                      pcirstin)
        
        variable v : pci_reg_type;
        variable chit, mhit0, mhit1, phit, hit, hosthit, ready, cwrite, retry : std_logic;
        variable cdata, cwdata : std_logic_vector(31 downto 0);
        variable comp : std_logic; -- Last transaction cycle on PCI bus
        variable mto, tto, term, ben_err, lto : std_logic;
        variable i : integer range 0 to NO_PCI_REGS;
        variable tad, mad : std_logic_vector(31 downto 0);
        variable pstart, habort, hstart_ack, wsdone, wmdone : std_logic;
        variable hstart, pabort, pstart_ack, pcidc, rtdone, rmdone : std_logic;
        variable fifort_limit, fifowt_limit, fiform_limit, fifowm_limit, fifowm_stop, t_valid : std_logic;
        variable d_ready, tabort, backendnr : std_logic;
        variable m_fifo_write, t_fifo_write, grant : std_logic;
        variable write_access, memwrite, memread, read_match, m_read_side, t_read_side : std_logic;
        variable readt_dly : std_logic; -- 1 turnaround cycle
        variable bus_idle, data_transfer, data_transfer_r, data_phase, targ_d_w_data, targ_abort, m_request : std_logic;
        variable voe_ad : std_logic_vector(31 downto 0);
        variable oe_par   : std_logic;
        variable oe_ad    : std_logic;
        variable oe_ctrl  : std_logic;
        variable oe_cbe   : std_logic;
        variable oe_frame : std_logic;
        variable oe_irdy  : std_logic;
        variable oe_req   : std_logic;
        variable oe_perr  : std_logic;
        variable oe_serr  : std_logic;
        
    begin

        -- Process defaults
        v := r; v.pci.trdy := '1'; v.pci.stop := '1'; v.pci.frame := '1';
        v.pci.oe_ad := '1'; v.pci.devsel := '1'; v.pci.oe_frame := '1';
        v.pci.irdy := '1'; v.pci.req := '1'; hosthit := '0'; m_request := '0';
        v.pci.oe_req := '0'; v.pci.oe_cbe := '1'; v.pci.oe_irdy := '1';
        mto := '0'; tto := '0'; v.m.stop_req := '0'; lto := '0';
        cdata := (others => '0'); retry := '0'; t_fifo_write := '0';
        chit := '0'; phit := '0'; mhit0 := '0'; mhit1 := '0'; tabort := '0';
        readt_dly := '0'; m_fifo_write := '0'; voe_ad := roe_ad; 
        tad := r.pci.ad; mad := r.pci.ad; grant := pcii.gnt; d_ready := '0';
        m_read_side := not r2.s.fifo.side; t_read_side := not r2.m.fifo.side;
        v.m.rmdone := '0';
        
        write_access := not r.t.read and not pr.irdy and not pr.trdy;
        memwrite := r.t.msel and r.t.lwrite and not r.t.read;
        memread := r.t.msel and not r.t.lwrite and r.t.read;

        -- Synch registers
        hstart := r.trans(0);
        pabort := r.trans(1);
        pstart_ack := r.trans(2);
        pcidc := r.trans(3);
        rtdone := r.trans(4);
        rmdone := r.trans(5);

        for i in 0 to NO_PCI_REGS - 1 loop
            v.syncs(i)(csync) := r2.trans(i);
            if csync /= 0 then v.syncs(i)(0) := r.syncs(i)(csync); end if;
        end loop;

        pstart     := r.syncs(0)(0);
        habort     := r.syncs(1)(0);
        hstart_ack := r.syncs(2)(0);
        backendnr  := r.syncs(3)(0);
        wsdone     := r.syncs(4)(0);
        wmdone     := r.syncs(5)(0);

        -- FIFO limit detector
        if r.t.fifo.raddr = FIFO_FULL then fifort_limit := '1'; else fifort_limit := '0'; end if;
        if r.t.fifo.waddr = FIFO_FULL then fifowt_limit := '1'; else fifowt_limit := '0'; end if;
        if r.m.fifo.raddr = FIFO_FULL then fiform_limit := '1'; else fiform_limit := '0'; end if;
        if r.m.fifo.waddr = FIFO_FULL then fifowm_limit := '1'; else fifowm_limit := '0'; end if;
        if r.m.fifo.waddr(FIFO_DEPTH - 2 downto 1) = FIFO_FULL(FIFO_DEPTH - 2 downto 1) then fifowm_stop := '1'; else fifowm_stop := '0'; end if;

        -- useful control variables
        --if (r.t.laddr = r.page & r.t.addr(MADDR_WIDTH-2 downto 0) or r.t.laddr = r2.dmapage & r.t.addr(DMAMADDR_WIDTH-1 downto 0))
        if (r.t.laddr(31 downto 2) = r.page & r.t.addr(MADDR_WIDTH-2 downto 2) -- bug fix match if byte access 
            or r.t.laddr(31 downto 2) = r2.dmapage & r.t.addr(DMAMADDR_WIDTH-1 downto 2)) 
            and (r.t.lcbe = pr.cbe) -- bug fix match byte access
            and (r.t.lburst = r.t.burst) then read_match := r.t.pending; else read_match := r.t.csel or r.t.psel; end if;

--    if (pr.cbe = "0000" and r.t.lsize = "10") or (pr.cbe = "1100" and r.t.lsize = "01") or (pr.cbe = "1110" and r.t.lsize = "00")
-- pragma translate_off
--    or (pr.cbe = "XXXX") -- For simulation purposes
-- pragma translate_on
--    then ben_err := '0'; else ben_err := '1'; end if;
        ben_err := '0';
        
        if r.stat.dpe = '0' then v.stat.dpe := not (r.pci.perr and r.pci.serr); end if;

-------------------------
----- PCI TARGET --------
-------------------------
        
        -- Data valid?
        if ((wmdone and not r.t.lwrite) = '1' and (r.t.fifo.raddr + '1') = r2.m.fifo.waddr) then t_valid := '0';
        else t_valid := not fifowt_limit or not r.t.fifo.side; end if;

        -- Step addresses
        if (r.t.state = s_data or r.t.state = turn_ar or r.t.state = backoff) then
            --if (pcii.irdy or r.pci.trdy) = '0' then
            if (pcii.irdy or r.t.trdy_del) = '0' then
                v.t.addr := r.t.addr + ((r.t.csel and r.t.read) & "00");
                readt_dly := '1';
                if r.t.msel = '1' then
                    -- **** ???? **** Is r2.m.fifo.side really synced here ??? *** may need to be changed *** [nisse]
                    v.t.wdel := (fifort_limit and r2.m.fifo.side) or r.t.lwrite;
                    v.t.fifo.raddr := r.t.fifo.raddr + (r.t.read and not fifort_limit and t_valid);
                end if;
            end if;
            if write_access = '1' then
                v.t.fifo.waddr := r.t.fifo.waddr + (r.t.msel and not r.t.read and not ben_err);
                t_fifo_write := r.t.msel;
                v.t.addr := r.t.addr + ((r.t.csel and not r.t.read) & "00");
            end if;
            tabort := habort;
        else v.t.wdel := '0'; end if;

        -- signal to hold target while last word is transfered
        if (fifort_limit and not (pcii.irdy or r.t.trdy_del) and not r.t.thold) = '1' then -- should be r.pci.trdy 
          v.t.thold := '1';
        elsif (r.t.thold and not (pcii.irdy or r.t.trdy_del)) = '1' then -- should be r.pci.trdy
          v.t.thold := '0';
        end if;


        -- Config space read access
        case r.t.addr(7 downto 2) is
            when "000000" =>      -- 0x00, device & vendor id
                cdata := conv_std_logic_vector(DEVICE_ID, 16) &
                         conv_std_logic_vector(VENDOR_ID, 16);
            when "000001" =>      -- 0x04, status & command
                cdata(1) := r.comm.men;
                cdata(2) := r.comm.msen;
                cdata(4) := r.comm.mwie;
                cdata(6) := r.comm.per;
                cdata(8) := r.comm.ser;
                cdata(24) := r.stat.dped;
                cdata(26) := '1';
                cdata(27) := r.stat.sta;
                cdata(28) := r.stat.rta;
                cdata(29) := r.stat.rma;
                cdata(30) := r.stat.sse;
                cdata(31) := r.stat.dpe;
            when "000010" =>      -- 0x08, class code & revision
                cdata(31 downto 0) := conv_std_logic_vector(CLASS_CODE,24) & conv_std_logic_vector(REV,8) ;
            when "000011" =>      -- 0x0C, latency & cacheline size
                cdata(7 downto 0) := r.cline;
                cdata(15 downto 8) := r.ltim;
            when "000100" =>      -- 0x10, BAR0
                cdata(31 downto MADDR_WIDTH) := r.bar0;
            when "000101" =>      -- 0x14, BAR1
                cdata(31 downto DMAMADDR_WIDTH) := r.bar1;
            when "001111" =>      -- 0x3C, Interrupts & Latency timer settings
                cdata(7 downto 0) := r.intline; -- Interrupt line
                cdata(8) := '1'; -- Use interrupt pin INTA#
                if fifodepth < 11 then cdata(fifodepth+13) := '1'; end if; --Define wanted burst period
            when others =>
        end case;

        -- Config space write access
        cwdata := pr.ad;
        if pr.cbe(3) = '1' then cwdata(31 downto 24) := cdata(31 downto 24); end if;
        if pr.cbe(2) = '1' then cwdata(23 downto 16) := cdata(23 downto 16); end if;
        if pr.cbe(1) = '1' then cwdata(15 downto  8) := cdata(15 downto  8); end if;
        if pr.cbe(0) = '1' then cwdata( 7 downto  0) := cdata( 7 downto  0); end if;
        if (r.t.csel and write_access) = '1' then
            case r.t.addr(7 downto 2) is
                
                when "000001" =>      -- 0x04, status & command
                    -- Command register
                    v.comm.men := cwdata(1);
                    if MASTER = 1 then v.comm.msen := cwdata(2); end if;
                    v.comm.mwie := cwdata(4);
                    v.comm.per := cwdata(6);
                    v.comm.ser := cwdata(8);
                    
                    -- Status register, sticky bits
                    v.stat.dped := r.stat.dped and not cwdata(24);
                    v.stat.sta  := r.stat.sta  and not cwdata(27); 
                    v.stat.rta  := r.stat.rta  and not cwdata(28); 
                    v.stat.rma  := r.stat.rma  and not cwdata(29); 
                    v.stat.sse  := r.stat.sse  and not cwdata(30); 
                    v.stat.dpe  := r.stat.dpe  and not cwdata(31);
                    
                when "000011" =>      -- 0x0c, latency & cacheline size
                    if FIFO_DEPTH <= 7 then v.cline(FIFO_DEPTH - 1 downto 0) := cwdata(FIFO_DEPTH - 1 downto 0);
                    else v.cline := cwdata(7 downto 0); end if;
                    v.ltim := cwdata(15 downto 8);
                    
                when "000100" =>      -- 0x10, BAR0
                    v.bar0 := cwdata(31 downto MADDR_WIDTH);
                    if v.bar0 = zero(31 downto MADDR_WIDTH) then v.bar0_conf := '0'; else v.bar0_conf := '1'; end if;
                    
                when "000101" =>      -- 0x14, BAR1
                    v.bar1 := cwdata(31 downto DMAMADDR_WIDTH);
                    if v.bar1 = zero(31 downto DMAMADDR_WIDTH) then v.bar1_conf := '0'; else v.bar1_conf := '1'; end if;
                    
                when "001111" =>  -- 0x3C, Interrupts & Latency timer settings
                    v.intline := cwdata(7 downto 0); -- Interrupt line
                when others =>
            end case;
        end if;

        -- Page bar write
        if (r.t.psel and write_access) = '1' then
            v.page := pr.ad(31 downto MADDR_WIDTH - 1);
            v.bt_enable := pr.ad(0);
        end if;

        -- Command and address decode
        case pr.cbe is
            when CONF_READ | CONF_WRITE =>
                if pr.ad(1 downto 0) = "00" then chit := '1'; end if;
                if pr.host = '0' then --Active low
                    if pr.ad(31 downto 11) = "000000000000000000000" then hosthit := '1'; end if;
                end if;
            when MEM_READ | MEM_WRITE =>
                if pr.ad(31 downto MADDR_WIDTH) = r.bar0 then
                    phit := r.bar0_conf and pr.ad(MADDR_WIDTH - 1);
                    mhit0 := r.bar0_conf and not pr.ad(MADDR_WIDTH - 1);
                elsif pr.ad(31 downto DMAMADDR_WIDTH) = r.bar1 then
                    mhit1 := r.bar1_conf;
                end if;
            when MEM_R_MULT | MEM_R_LINE | MEM_W_INV =>
                if pr.ad(31 downto MADDR_WIDTH - 1) = r.bar0 & '0' then mhit0 := r.bar0_conf;
                elsif pr.ad(31 downto DMAMADDR_WIDTH) = r.bar1 then mhit1 := r.bar1_conf; end if;
            when others => phit := '0'; mhit0 := '0'; chit := '0'; mhit1 := '0';
        end case;

        -- SERR, address phase parity error. Treat as non hit.
        v.pci.serr    := '1';
        v.pci.oe_serr := '1';
        if pr.frame = '0' then
            if ( (pcii.par xor xorv(pr.ad & pr.cbe)) = '1') then
                v.pci.serr := '0';
                chit := '0'; phit := '0'; mhit0 := '0'; mhit1 := '0'; 
                if r.comm.ser = '1' then
                    v.pci.oe_serr := '0';
                    v.stat.sse := '1';
                end if;
            end if;
        end if;
        
        -- Hit detect
        hit := r.t.csel or r.t.msel or r.t.psel;

        if (hstart and r.pci.devsel) = '1' then
            if (r.t.pending or r.t.lwrite) = '0' then
                hstart := not hstart_ack;
                v.t.fifo.raddr := (others => '0');
            end if;
        end if;

        -- Ready to transfer data  
        if ((r.t.csel and not readt_dly) or r.t.psel) = '1'
            or ((((memwrite and not r.pci.devsel) = '1')
                 -- Changed to transfer last word (instead of delaying trdy) [nisse]
                 --or (memread = '1' and not (hstart_ack and v.t.wdel) = '1')) and ben_err = '0')
                 or (memread = '1' and not (hstart_ack and r.t.wdel) = '1')) and ben_err = '0')
        then ready := '1'; else ready := '0'; t_read_side := r.t.read and not hstart; end if;

        v.t.ready_del := ready;

        -- Target timeout counter
        --if (hit and pr.trdy and not (pr.frame and pr.irdy)) = '1' then 
        --if (hit and pr.trdy and not (pr.frame and pr.irdy) and v.t.wdel) = '1' then 
        if (hit and pr.trdy and not (pr.frame and pr.irdy) and not ready) = '1' then
            if r.t.cnt /= "000" then v.t.cnt := r.t.cnt - 1;
            else tto := '1'; end if;
        else v.t.cnt := (0 => '0', others => '1'); end if;

--    -- Ready to transfer data
--    if ((r.t.csel and not readt_dly) or r.t.psel) = '1'
--       or ((((memwrite and not r.pci.devsel) = '1')
--       or (memread = '1' and not (hstart_ack and v.t.wdel) = '1')) and ben_err = '0')
--       then ready := '1'; else ready := '0'; t_read_side := r.t.read and not hstart; end if;

        -- Terminate current transaction
        if (((r.t.fifo.waddr >= (FIFO_FULL - "10") and r.t.fifo.side = '1')
             or (t_valid = '0') or r.pci.stop = '0') and pcii.frame = '0')
            or ((r.t.read xor r.t.lwrite) = '0' and r.pci.devsel = '0')
            or (tto = '1') or (ben_err = '1')
        then 
	  term := '1'; 
	else term := '0'; end if;

        -- Retry transfer
        if r.t.state = b_busy then
            if not ((r.t.read and not r.t.lwrite and hstart_ack and read_match) = '1'
                    or (r.t.read or hstart or hstart_ack) = '0'
                    or ((r.t.csel or r.t.psel) and not hstart and not hstart_ack) = '1')
            then 
		retry := '1'; 
	    end if;
        end if;

        -- Target state machine
        case r.t.state is

            when idle  =>
                v.t.thold := '0';  
                v.t.thold2 := '0';  

                if pr.frame = '0' then v.t.state := b_busy; end if; -- !HIT ?
                v.t.addr := pr.ad;
                if readpref = 1 then v.t.burst := '1';
                else v.t.burst := pr.cbe(3); end if;
                v.t.read := not pr.cbe(0); v.t.mult := not pr.cbe(1);
                v.t.csel := (pr.idsel or hosthit) and chit; v.t.psel := phit;
                v.t.msel := r.comm.men and (mhit0 or mhit1); v.t.barsel := mhit1;
            when turn_ar =>
                
                if pr.frame = '1' then 
                    v.t.state := idle;
                    v.t.fifo.raddr := (others => '0'); -- fix reset fifo read address 
                else v.t.state := b_busy; end if; -- !HIT ?
                v.t.addr := pr.ad; v.t.wdel := '1';
                if readpref = 1 then v.t.burst := '1';
                else v.t.burst := pr.cbe(3); end if;
                v.t.read := not pr.cbe(0); v.t.mult := not pr.cbe(1);
                v.t.csel := (pr.idsel or hosthit) and chit; v.t.psel := phit;
                v.t.msel := r.comm.men and (mhit0 or mhit1); v.t.barsel := mhit1;
            when b_busy  =>
                v.t.thold := '0';
                v.t.thold2 := '0';
                if (pr.frame and pr.irdy) = '1' then
                    v.t.state := idle;

                elsif hit = '1' then
                    v.t.state := s_data;
                    v.t.fifo.raddr := r.t.fifo.raddr + (r.t.read and r.t.msel);
                    readt_dly := '1';
                    
                    if r.t.pending = '0' then
                        v.t.pending := retry and not hstart_ack;
                    end if;
                    
                end if;
--      else v.t.state := backoff; end if;
--      We should not go to back off if the access wasn't to us
                
            when s_data  =>
                
                if r.t.pending = '1' then v.t.pending := not ((habort or not r.pci.trdy) and read_match); end if;
                if (pcii.frame = '0' and r.pci.stop ='0' and (r.pci.trdy or not pcii.irdy) = '1') then
                    v.t.state := backoff;
                    if r.t.last = '0' then v.t.last := r.t.msel and r.t.lwrite and v.t.wdel; end if;
                    v.t.fifo.raddr := r.t.fifo.raddr - (r.t.read and r.t.msel and not fifort_limit);
--      elsif (pcii.frame = '1' and (r.pci.trdy = '0' or r.pci.stop = '0')) then
                elsif (pcii.frame = '1' and (r.t.trdy_del = '0' or r.pci.stop = '0')) then -- (send last word in fifo) bug fix *** 
                    v.t.state := turn_ar;
                    if r.t.last = '0' then v.t.last := r.t.msel and r.t.lwrite and v.t.wdel; end if;
                    v.t.fifo.raddr := r.t.fifo.raddr - (r.t.read and r.t.msel and not fifort_limit);
                end if;
            when backoff =>
                
                if pcii.frame = '1' then v.t.state := turn_ar; end if;
        end case;

        -- #TRDY assert
        --if (v.t.state = s_data and habort = '0' and ready = '1' and retry = '0') then v.pci.trdy := '0'; end if;
        -- Changed to only deassert trdy when irdy is asserted [nisse] 
        if (v.t.state = s_data and habort = '0' and (ready or (pcii.irdy and not r.pci.trdy)) = '1' and retry = '0') then v.pci.trdy := '0'; end if;

        -- #STOP assert
        --if (v.t.state = backoff or (v.t.state = s_data and ((tabort or ((term or retry) and not habort)) = '1'))) then
        -- Changed to only deassert stop when irdy is asserted [nisse]
        if (v.t.state = backoff or (v.t.state = s_data and ((tabort or (((term and (not pcii.irdy or not r.pci.stop)) or retry) and not habort)) = '1'))) then
            v.pci.stop := '0'; end if;
        
        -- #DEVSEL assert
        if (((v.t.state = backoff and r.pci.devsel = '0') or v.t.state = s_data) and (read_match and tabort) = '0') then v.pci.devsel := '0'; end if;
        
        -- Enable #TRDY, #STOP and #DEVSEL
        if (v.t.state = s_data) or (v.t.state = backoff) or (v.t.state = turn_ar) then
            v.pci.oe_ctrl := not hit;
        else v.pci.oe_ctrl := '1'; end if;

        -- Signaled target abort
        if (r.pci.devsel and not (r.pci.stop or r.pci.oe_ctrl)) = '1' then v.stat.sta := '1'; end if;

        if (fifort_limit and v.t.thold) = '1' then --v.pci.trdy := '0';
        elsif (r.t.thold and not v.t.thold) = '1' then --v.pci.trdy := '1'; 
        end if;
        
        -- Removed, (ready is delayed instead) [nisse]
        --if r.t.state = s_data and v.t.state = s_data and r.pci.trdy = '0' 
        --    and v.pci.trdy = '1' and v.t.wdel = '1' and pcii.frame = '0' then -- (send last word in fifo) bug fix *** 
        --    v.t.trdy_del := '0';
            --v.pci.trdy := '0';
            --v.t.trdy_del := v.pci.trdy;
        --else
            v.t.trdy_del := v.pci.trdy;
        --end if;

        if r.t.state = s_data and r.pci.trdy = '1' and v.pci.trdy = '0' and pcii.frame = '0' then -- bug fix *** 
            readt_dly := '1';
            v.t.fifo.raddr := r.t.fifo.raddr + (r.t.read and not fifort_limit and t_valid);
        end if;

        -- Latched signals to AHB backend
        if (r.t.state = b_busy) then
            if (hstart or hstart_ack) = '0' then -- must be idle
                v.t.lwrite := not r.t.read;
                
                if r.t.msel = '1' then
                    v.t.lburst := r.t.burst;
                    v.t.lcbe := pr.cbe; 
                    if r.t.barsel = '0' then v.t.laddr := r.page & r.t.addr(MADDR_WIDTH-2 downto 2) & "00";
                    else  v.t.laddr := r2.dmapage & r.t.addr(DMAMADDR_WIDTH-1 downto 2) & "00"; end if;
                    v.t.lmult :=  r.t.mult;
                    rtdone := '0'; v.t.fifo.waddr := (others => '0');
                    hstart := r.t.read and r.t.msel;
                end if;
            end if;
        end if;
        
        -- Read data mux
        if r.t.csel = '1' then tad := cdata;
        elsif r.t.psel = '1' then
            tad(31 downto MADDR_WIDTH-1) := r.page;
            tad(MADDR_WIDTH-2 downto 0) := zero32(MADDR_WIDTH-2 downto 1) & r.bt_enable;
--    elsif (r.t.state = b_busy or (r.pci.trdy or pcii.irdy) = '0') then tad := fifo1o.rdata(31 downto 0);
        elsif (r.t.state = b_busy or (r.pci.trdy or pcii.irdy) = '0' or r.t.wdel = '1') then tad := byte_twist(fifo1o.rdata(31 downto 0), r.bt_enable); -- bug fix *** 
        end if;

        -- FIFO controller
        if ((fifowt_limit and write_access) = '1' or (r.t.last or rtdone) = '1') then
            if hstart = hstart_ack then
                if rtdone = '0' then hstart := not hstart_ack; v.t.fifo.side := hstart; end if;
                if r.t.last = '1' then rtdone := '1'; v.t.last := '0';
                else v.t.fifo.waddr := (others => '0');
                     if rtdone = '1' then
                         rtdone := '0'; hstart := '0'; v.t.fifo.side := '0';
                     end if;
                end if;
            end if;
        end if;

        -- Changed to only reset address counter when last word is transfered [nisse]
        --if (fifort_limit and v.t.wdel) = '1' then
        --    if hstart_ack = '1' then hstart := '0'; v.t.fifo.raddr := (others => '0');
        --    else v.t.fifo.raddr := (others => '0'); end if;
        --end if;
         if hstart_ack = '1' and (fifort_limit and r.t.thold and not v.t.thold) = '1' then 
           hstart := '0'; v.t.fifo.raddr := (others => '0');
         end if;

        -- Hold AD if irdy waitstates after fifo switch [nisse]
        if r.t.state = s_data and pcii.irdy = '1' and r.pci.trdy = '1' and v.pci.trdy = '0' and r.t.thold2 = '0' then v.t.thold2 := '1';
        elsif r.t.thold2 = '1' and pcii.irdy = '0' then v.t.thold2 := '0'; end if;
----------------------        
--- PCI TARGET END ---
----------------------

------------------
--- PCI MASTER ---
------------------

        if MASTER = 1 then

            bus_idle := pcii.frame and pcii.irdy;
            data_transfer := not (pcii.trdy or r.pci.irdy);
            data_transfer_r := not (pr.trdy or pr.irdy);
            data_phase := not ((pcii.trdy and pcii.stop) or r.pci.irdy);
            targ_d_w_data := not (pr.stop or pr.trdy);
            targ_abort := pr.devsel and not pr.stop;


            -- Request from AHB backend to start PCI transaction
            if (pstart and not pstart_ack) = '1' then
                if (r.m.fstate = idle and r.m.request = '0') then
                    v.m.request := '1';
                    rmdone := '0'; v.m.valid := '1';
                    v.m.fifo.waddr := (others => '0');
                    v.m.hwrite := r2.s.pcicomm(0);
                end if;
            end if;

            -- Master timeout and DEVSEL timeout
            if ((pr.irdy and not pr.frame) or (pr.devsel and not r.pci.oe_frame)) = '1' then
                if r.m.cnt /= "000" then v.m.cnt := r.m.cnt - 1;
                else mto := '1'; end if;
            else v.m.cnt := (others => '1'); end if;

            -- Latency counter
            if r.pci.frame = '0' then
                if r.m.ltim > "00000000" then v.m.ltim := r.m.ltim - '1';
                else lto := '1'; end if;
            else
                v.m.ltim := r.ltim;
            end if;

            -- Last data
            case r2.s.pcicomm is
                when MEM_R_MULT | MEM_R_LINE =>
                    if (r.m.fifo.waddr >= (FIFO_FULL - "10") and r.m.fifo.side = '1') then
                        comp := '1';
                    else comp := '0'; end if;
                when MEM_WRITE | MEM_W_INV => comp := not r.m.valid;
                when others => comp := '1';
            end case;

            -- Minimun latency
            --if lto = '0' then grant := '0'; end if;
            if lto = '0' then grant := '0'; -- latency timer bug fix  
            elsif pcii.gnt = '1' then v.m.lto := '1'; end if; 

            -- Data parity error detected
            if (r.m.fstate /= idle and r.stat.dped = '0') then v.stat.dped := r.comm.per and not pcii.perr; end if;

            -- FIFO control state machine
            case r.m.fstate is
                when idle =>
                    
                    v.m.lto := '0'; 
                    if (r.m.request and bus_idle and not pcii.gnt) = '1' and (r.m.state = idle or r.m.state = dr_bus) then
                        v.m.fstate := addr; v.m.fifo.waddr := (others => '0'); v.m.fifo.side := '0'; m_request := '1';
                    end if;
                when addr =>
                    
--      if (wsdone = '1' and (r.m.fifo.raddr + '1') = r2.s.fifo.waddr) then v.m.valid := '0'; end if;
                    if (wsdone = '1' and ((r.m.fifo.raddr + '1') = r2.s.fifo.waddr) and (m_read_side = r2.s.last_side)) then v.m.valid := '0'; end if; --bug fix kc
                    
                    if fiform_limit = '1' then v.m.fstate := last1;
                    else v.m.fstate := incr; end if;
                    v.m.fifo.raddr := r.m.fifo.raddr + r.m.hwrite;
                    v.m.first := '1'; v.m.firstw := '1';
                when incr =>
                    
                    d_ready := '1';
                    
                    if r.m.valid = '0' then v.m.lto := '0'; end if; -- dont look at latency timer if done 

                    if data_transfer = '1' then
                        
                        --if fiform_limit = '1' then v.m.fstate := last1; v.m.split := not backendnr; end if;
                        if fiform_limit = '1' and r.m.lto = '0' then v.m.fstate := last1; v.m.split := not backendnr; end if; -- bug fix latency timer

--        if (wsdone = '1' and (r.m.fifo.raddr + pcii.stop) = r2.s.fifo.waddr) then v.m.valid := '0'; end if;
                        if (wsdone = '1' and ((r.m.fifo.raddr + pcii.stop) = r2.s.fifo.waddr) and (m_read_side = r2.s.last_side)) then v.m.valid := '0'; end if; --bug fix kc

                        v.m.fifo.raddr := r.m.fifo.raddr + r.m.hwrite;
                        v.m.first := '0';
                    end if;
                    if data_transfer_r = '1' then
                        if fifowm_stop = '1' then
                            if r.m.firstw = '1' then
                                if (fifowm_limit and pr.stop) = '1' then v.m.fifo.side := not r.m.fifo.side; v.m.firstw := '0'; pstart_ack := pstart; end if;
                            end if;
                        end if;
                        v.m.fifo.waddr := r.m.fifo.waddr + (not r.m.hwrite);
                    end if;
                    if pr.stop = '0' then
                        if targ_abort = '1' then v.m.fstate := abort;
                        elsif targ_d_w_data = '1' then v.m.fstate := ttermwd;
                        elsif r.m.first = '1' then v.m.fstate := t_retry;
--        else v.m.fstate := ttermnd; end if;
                        else  -- bug fix *** 
--           if r.m.fifo.waddr = "0000000" then v.m.rmdone := '1'; end if;
                            if r.m.fifo.waddr = zero32(FIFO_DEPTH - 2 downto 0) then v.m.rmdone := '1'; end if;
                            v.m.fstate := ttermnd;
                        end if;
                    elsif mto = '1' then v.m.fstate := abort;
                                         --elsif grant = '1' then -- pci_gnt bug fix 
                                         --  if r.m.hwrite = '0' then rmdone := not r.m.fifo.side; v.m.fifo.side := '1'; v.m.fstate := done; pstart_ack := pstart;
                                         --  else v.m.fstate := idle; end if;
                                         
                                         --elsif (pr.frame and not r.m.first) = '1' then
                    elsif (pr.frame and not pr.trdy and not r.m.first) = '1' then -- not done if target not ready *** bug fix
                        if r.m.hwrite = '0' then rmdone := not r.m.fifo.side; v.m.fifo.side := '1'; v.m.fstate := done; pstart_ack := pstart;
                                                 --else v.m.fstate := done; pstart_ack := pstart; end if;
                        else 
                            if r.m.lto = '1' then -- latency timer bug fix
                                v.m.fifo.raddr := r.m.fifo.raddr - r.m.hwrite;
                                v.m.fstate := idle;
                            else
                                v.m.fstate := done; pstart_ack := pstart; 
                            end if;
                        end if;
                    elsif (pr.devsel and not r.m.first) = '1' then
                        if r.m.hwrite = '0' then rmdone := not r.m.fifo.side; v.m.fifo.side := '1'; v.m.fstate := done; pstart_ack := pstart;
                        else v.m.fstate := idle; end if;
                    end if;
                when last1 =>

                    if (pr.trdy and not pr.stop) = '1' then
                        if targ_abort = '1' then v.m.fstate := abort;
                        elsif targ_d_w_data = '1' then v.m.fstate := ttermwd;
                        else v.m.fstate := ttermnd; v.m.valid := '1'; end if;
                        --elsif (pr.frame and not r.m.first and not r.m.split) = '1' then v.m.fstate := done; rmdone := not r.m.fifo.side; pstart_ack := pstart;
                        -- not done if target not ready *** bug fix
                    elsif (pr.frame and not pr.trdy and not r.m.first and not r.m.split) = '1' then v.m.fstate := done; rmdone := not r.m.fifo.side; pstart_ack := pstart;
                    elsif data_transfer = '1' then
                        if r.m.valid = '1' then v.m.fstate := sync; pstart_ack := pstart;
                        else v.m.fstate := done; rmdone := not r.m.fifo.side; pstart_ack := pstart; end if;
                    else d_ready := '1';
                    end if;
                when sync =>
                    
                    if pstart = not pstart_ack then
                        v.m.split := '0';
                        if ((r.m.split or (pr.trdy and not pr.stop and not r.m.split))  = '1' or r.m.state /= m_data) then v.m.fstate := idle; d_ready := '1';
                        else
                            --if (wsdone = '1' and (r.m.fifo.raddr + '1') = r2.s.fifo.waddr) then v.m.valid := '0'; end if;
                            if (r2.trans(4) = '1' and (r.m.fifo.raddr + '1') = r2.s.fifo.waddr) then v.m.valid := '0'; end if; -- not synced wsdone
                            v.m.fstate := incr; data_transfer := '1'; v.m.fifo.raddr := r.m.fifo.raddr + r.m.hwrite; d_ready := '1';
                        end if;
                    else m_read_side := '1';
                    end if;
                when t_retry =>
                    
                    v.m.fifo.raddr := r.m.fifo.raddr - r.m.hwrite; v.m.fstate := idle;

                when ttermwd =>
                    
                    if data_transfer = '1' then v.m.fifo.raddr := r.m.fifo.raddr + r.m.hwrite;
                    elsif pr.trdy = '1' then v.m.fifo.raddr := r.m.fifo.raddr - r.m.hwrite;
                                             if (r.m.hwrite and r.m.valid) = '1' then v.m.fstate := idle;
                                             else v.m.fstate := done; rmdone := not r.m.fifo.side; v.m.fifo.side := '1'; pstart_ack := pstart; end if;
                    end if;
                when ttermnd =>
                    
                    if r.m.hwrite = '1' then
                        v.m.fifo.raddr := r.m.fifo.raddr - '1';
--          if (r.m.fifo.raddr /= (r2.s.fifo.waddr + '1') or wsdone = '0') then v.m.valid := '1'; v.m.fstate := idle; -- bug fix *** 
                        if (r.m.fifo.raddr /= (r2.s.fifo.waddr + '1') or wsdone = '0' or r.m.valid = '1') then v.m.valid := '1'; v.m.fstate := idle;
                        else v.m.fstate := done; rmdone := not r.m.fifo.side; v.m.fifo.side := '1'; pstart_ack := pstart; end if;
--        else v.m.fstate := done; rmdone := not r.m.fifo.side; v.m.fifo.side := '1'; pstart_ack := pstart; end if;
                    else v.m.fstate := done; rmdone := (not r.m.fifo.side or r.m.rmdone); v.m.fifo.side := '1'; pstart_ack := pstart; end if; -- bug fix *** 
                when abort =>
                    
                    v.m.fifo.raddr := (others => '0'); v.m.fifo.waddr := (others => '0');
                    v.m.fstate := done; pstart_ack := pstart; pabort := '1';
                when done =>
                    
                    d_ready := '1'; comp := '1'; v.m.request := '0';
                    if (pstart or pstart_ack) = '0' then
                        v.m.fstate := wdone; v.m.fifo.raddr := (others => '0'); v.m.fifo.side := '0'; rmdone := '1';
                    else pstart_ack := pstart; end if;
                when wdone =>
                    
                    d_ready := '1'; comp := '1';
                    if (r.m.state = idle or r.m.state = dr_bus) then v.m.fstate := idle; pabort := '0';  end if;
            end case;

            -- PCI master state machine
            case r.m.state is
                when idle => -- Master idle
                    v.m.stopframe := '0'; 
                    if (pcii.gnt = '0' and bus_idle = '1') then
                        if m_request = '1' then v.m.state := addr;
                        else v.m.state := dr_bus; end if;
                    end if;
                when addr => -- Always one address cycle at the beginning of an transaction
                    v.m.stopframe := '0'; 
                    v.m.state := m_data;
                when m_data => -- Master transfers data
                    if r.pci.frame = '1' then v.m.stopframe := '1'; end if; -- *** 
                    if (r.pci.frame = '0') or ((r.pci.frame and pcii.trdy and pcii.stop and not mto) = '1') then
                        v.m.state := m_data;
                        if (r.pci.frame and not d_ready) = '1' then d_ready := '1'; end if;
                    elsif ((r.pci.frame and (mto or not pcii.stop)) = '1') then
                        v.m.state := s_tar;
                        v.m.stop_req := '1';
                    else v.m.state := turn_ar; end if;
                when turn_ar => -- Transaction complete
                    
                    if pcii.gnt = '0' then
                        if m_request = '1' then v.m.state := addr;
                        else v.m.state := dr_bus; end if;
                    else v.m.state := idle; end if;
                when s_tar => -- Stop was asserted
                    
                    if pcii.gnt = '0' then v.m.state := dr_bus;
                    else v.m.state := idle; end if;
                when dr_bus => -- Drive bus when parked on this agent
                    
                    if pcii.gnt = '1' then v.m.state := idle;
                    elsif m_request = '1' then v.m.state := addr; end if;
            end case;

            -- FIFO write strobe
            m_fifo_write := not r.m.hwrite and not pr.irdy and not (pr.trdy and (pr.stop or not r.trans(3))) and not r.pci.oe_irdy;

            -- PCI data mux
            if v.m.state = addr then
                if r.m.hwrite = '1' then mad := (r2.s.maddr + ((((not r2.s.fifo.side) & r.m.fifo.raddr)) & "00"));
                else mad := r2.s.maddr; end if;
            elsif (r.m.state = addr or data_transfer = '1') then mad := fifo3o.rdata(31 downto 0);
            end if;

            -- Target abort
            if ((pr.devsel and pr.trdy and not pr.gnt and not pr.stop) = '1') then v.stat.rta := '1'; end if;

            -- Master abort
            if mto = '1' then v.stat.rma := '1'; end if;

            -- Drive FRAME# and IRDY#
            if (v.m.state = addr or v.m.state = m_data) then v.pci.oe_frame := '0'; end if;

            -- Drive CBE#
            if (v.m.state = addr or v.m.state = m_data or v.m.state = dr_bus) then v.pci.oe_cbe := '0'; end if;

            -- Drive IRDY# (FRAME# delayed one pciclk)
            v.pci.oe_irdy := r.pci.oe_frame;

            -- FRAME# assert
            if (v.m.state = addr or (v.m.state = m_data and mto = '0' and v.m.stopframe = '0'  -- stopframe fix frame when pci_gnt is deasserted
                --and ((((pcii.stop or not d_ready) and not (comp or v.m.split or not v.m.valid)) and not grant)) = '1')) -- dont change frame when gnt = 1 if not irdy and trdy or stop
                  and ((((pcii.stop or not d_ready) and not (comp or v.m.split or not v.m.valid)) and not (grant and not pr.irdy and (not pcii.trdy or not pcii.stop) ) )) = '1'))
            then
                v.pci.frame := '0';
            end if;

            -- IRDY# assert
            if (v.m.state = m_data and ((d_ready or mto or (not r.m.valid) or (v.pci.frame and not r.pci.frame)) = '1'))  then v.pci.irdy := '0'; end if;

            -- REQ# assert
            if ((v.m.request = '1' and (r.m.fstate = idle or comp = '0')) and (v.m.stop_req or r.m.stop_req) = '0') then v.pci.req := '0'; end if;

            -- C/BE# assert
            if v.m.state = addr then v.pci.cbe := r2.s.pcicomm; else v.pci.cbe := r2.s.be; end if;

        end if;

---------------------
---PCI MASTER END ---
---------------------

----------------------        
--- SHARED SIGNALS ---
----------------------

        
        -- Drive PAR one clock after AD
        v.pci.oe_par := r.pci.oe_ad; 
        v.pci.par := xorv(r.pci.ad & r.pci.cbe); -- Default asserted by master
        
        -- PERR error
        v.pci.oe_perr := not(r.comm.per and r.pci.oe_par and not (pr.irdy and pr.trdy)) and (r.pci.oe_perr or r.pci.perr);
        v.pci.perr    := not (pcii.par xor xorv(pr.ad & pr.cbe)) or pr.irdy or pr.trdy; -- Detect parity error
        
        v.pci.ad := mad;  -- Default asserted by master

        -- Master drives AD
        if (v.m.state = addr or (v.m.state = m_data and r.m.hwrite = '1') or v.m.state = dr_bus) then
            v.pci.oe_ad := '0';
        end if;
        -- Target drives AD
        if r.t.read = '1' then
            if v.t.state = s_data then
                v.pci.oe_ad := '0';
                --v.pci.ad := tad; end if;
                -- Hold AD when master adds waitstates [nisse] 
                if (v.t.thold = '0' or (v.t.trdy_del = '0' and r.t.trdy_del = '0')) and v.t.thold2 = '0' and (pcii.irdy and not r.pci.trdy) = '0' then v.pci.ad := tad; end if;
            end if;
            if r.t.state = s_data then
                v.pci.par := xorv(r.pci.ad & pcii.cbe);
            end if;
        end if;
        
        v.noe_ad    := not v.pci.oe_ad;
        v.noe_ctrl  := not v.pci.oe_ctrl;
        v.noe_par   := not v.pci.oe_par;
        v.noe_req   := not v.pci.oe_req;
        v.noe_frame := not v.pci.oe_frame;
        v.noe_cbe   := not v.pci.oe_cbe;
        v.noe_irdy  := not v.pci.oe_irdy;
        v.noe_perr  := not v.pci.oe_perr;
        v.noe_serr  := not v.pci.oe_serr;
        
	if (scanen = 1) and (syncrst = 1) and (ahbmi.testen = '1') then
            voe_ad   := (others => ahbmi.testoen);
            oe_ad    := '1';
            oe_ctrl  := '1';
            oe_par   := '1';
            oe_req   := '1';
            oe_frame := '1';
            oe_cbe   := '1';
            oe_irdy  := '1';
            oe_perr  := '1';
            oe_serr  := '1';

        elsif oepol  = 0 then
	  if (syncrst = 1) and (pcirstin = '0') then
            voe_ad   := (others => '1');
            oe_ad    := '1';
            oe_ctrl  := '1';
            oe_par   := '1';
            oe_req   := '1';
            oe_frame := '1';
            oe_cbe   := '1';
            oe_irdy  := '1';
            oe_perr  := '1';
          else
            voe_ad   := (others => v.pci.oe_ad);
            oe_ad    := r.pci.oe_ad;
            oe_ctrl  := r.pci.oe_ctrl;
            oe_par   := r.pci.oe_par;
            oe_req   := r.pci.oe_req;
            oe_frame := r.pci.oe_frame;
            oe_cbe   := r.pci.oe_cbe;
            oe_irdy  := r.pci.oe_irdy;
            oe_perr  := r.pci.oe_perr;
            oe_serr  := r.pci.oe_serr;
          end if;
          
        else -- oepol = 1
	  if (syncrst = 1) and (pcirstin = '0') then
            voe_ad   := (others => '0');
            oe_ad    := '0';
            oe_ctrl  := '0';
            oe_par   := '0';
            oe_req   := '0';
            oe_frame := '0';
            oe_cbe   := '0';
            oe_irdy  := '0';
            oe_perr  := '0';
          else
            voe_ad   := (others => v.noe_ad);
            oe_ad    := r.noe_ad;
            oe_ctrl  := r.noe_ctrl;
            oe_par   := r.noe_par;
            oe_req   := r.noe_req;
            oe_frame := r.noe_frame;
            oe_cbe   := r.noe_cbe;
            oe_irdy  := r.noe_irdy;
            oe_perr  := r.noe_perr;
            oe_serr  := r.noe_serr;
          end if;
        end if;

--------------------------        
--- SHARED SIGNALS END ---
--------------------------
        
        v.trans(0) := hstart;
        v.trans(1) := pabort;
        v.trans(2) := pstart_ack;
        v.trans(3) := pcidc;
        v.trans(4) := rtdone;
        v.trans(5) := rmdone;

        if prrst = '0' then
            v.t.state := idle; v.m.state := idle; v.m.fstate := idle;
            v.bar0 := (others => '0'); v.bar0_conf := '0';
            v.bar1 := (others => '0'); v.bar1_conf := '0';
            v.t.msel := '0'; v.t.csel := '0';
            v.t.pending := '0'; v.t.lwrite := '0';
            v.bt_enable := '1'; -- twisting enabled by default, changed through page0
            v.page(31 downto 30) := "01";
            v.page(29 downto MADDR_WIDTH-1) := zero32(29 downto MADDR_WIDTH-1);
            v.pci.par := '0';
            v.comm.msen := not pr.host;
            v.comm.men := '0';
            v.comm.mwie := '0';
            v.comm.per := '0';
            v.comm.ser := '0';
            v.stat.rta := '0';
            v.stat.rma := '0';
            v.stat.sta := '0';
            v.stat.dped := '0';
            v.stat.dpe := '0';
            v.stat.sse := '0';
            v.cline := (others => '0');
            v.ltim := (others => '0');
            v.intline := (others => '0');
            v.trans := (others => '0');
            v.t.fifo.waddr := (others => '0');
            v.t.fifo.raddr := (others => '0');
            v.m.fifo.waddr := (others => '0');
            v.m.fifo.raddr := (others => '0');
            v.t.fifo.side := '0';
            v.m.fifo.side := '0';
            v.m.request := '0';
            v.m.hwrite := '0';
            v.m.valid := '1';
            v.m.split := '0';
            v.m.last := '0'; v.t.last := '0';
            v.t.laddr := (others => '0'); -- to remove x problem in gate-simulation
        end if;


        cbe_fifoi.wen   <= t_fifo_write;
        cbe_fifoi.waddr <= r.t.fifo.side & r.t.fifo.waddr;
        cbe_fifoi.wdata(3 downto 0) <= pr.cbe;

        fifo2i.wen   <= t_fifo_write;
        fifo2i.waddr <= r.t.fifo.side & r.t.fifo.waddr;
        fifo2i.wdata <= byte_twist(pr.ad, r.bt_enable);
        
        fifo1i.ren   <= '1';
        fifo1i.raddr <= t_read_side & (r.t.fifo.raddr + readt_dly);
        
        fifo4i.wen   <= m_fifo_write;
        fifo4i.waddr <= r.m.fifo.side & r.m.fifo.waddr;
        fifo4i.wdata <= pr.ad;
        
        fifo3i.ren   <= '1';
        fifo3i.raddr <= m_read_side & (r.m.fifo.raddr + data_transfer);
        
        rin <= v;
        rioe_ad <= voe_ad;

        
        pcio.cbeen    <= (others => oe_cbe);
        pcio.cbe      <= r.pci.cbe;

        pcio.vaden    <= roe_ad; 
        pcio.aden     <= oe_ad;
        pcio.ad       <= r.pci.ad;

--    pcio.trdy     <= r.pci.trdy;
        pcio.trdy     <= r.t.trdy_del; -- (send last word in fifo) bug fix *** 
        pcio.ctrlen   <= oe_ctrl;
        pcio.trdyen   <= oe_ctrl;
        pcio.devselen <= oe_ctrl;
        pcio.stopen   <= oe_ctrl;
        pcio.stop     <= r.pci.stop;
        pcio.devsel   <= r.pci.devsel;
        pcio.par      <= r.pci.par;
        pcio.paren    <= oe_par;

        pcio.perren   <= oe_perr;
        pcio.perr     <= r.pci.perr;

        pcio.serr     <= r.pci.serr;
        pcio.serren   <= oe_serr;
        
        pcio.reqen    <= oe_req;
        pcio.req      <= r.pci.req;
        pcio.frameen  <= oe_frame;
        pcio.frame    <= r.pci.frame;
        pcio.irdyen   <= oe_irdy;
        pcio.irdy     <= r.pci.irdy;

    end process;

    rstinputgen : if hostrst = 0 generate
        pcirstin <= pcii.rst;
        pcio.rst <= '1';
    end generate;
    hostrstgen : if hostrst = 1 generate
        --pcirstin <= rst when pcii.host = '0' else pcii.rst;
        pcirstin <= pcii.rst;
        pcio.rst <= rst when pcii.host = '0' else '1';
    end generate;

    
    pcirst <= ahbmi.testrst when (scanen = 1) and (ahbmi.testen = '1') 
	else  pcirstin;

    pr_regs : process (pciclk)
    begin
      if rising_edge (pciclk) then
        pr.ad         <= to_x01(pcii.ad);
        pr.cbe        <= to_x01(pcii.cbe);
        pr.devsel     <= to_x01(pcii.devsel);
        pr.frame      <= to_x01(pcii.frame);
        pr.idsel      <= to_x01(pcii.idsel);
        pr.irdy       <= to_x01(pcii.irdy);
        pr.trdy       <= to_x01(pcii.trdy);
        pr.par        <= to_x01(pcii.par);
        pr.stop       <= to_x01(pcii.stop);
        prrst         <= to_x01(pcirstin);
        pr.gnt        <= to_x01(pcii.gnt);
        pr.host       <= to_x01(pcii.host);
      end if;
    end process;

    regs : process (pciclk, pcirst)
    begin
      if rising_edge (pciclk) then
        r <= rin;
      end if;
      if (syncrst = 0) and (pcirst = '0') then -- asynch reset required
        r.pci.oe_ad <= '1'; r.pci.oe_ctrl <= '1'; r.pci.oe_par <= '1';
        r.pci.oe_req <= '1'; r.pci.oe_frame <= '1'; r.pci.oe_cbe <= '1';
        r.pci.oe_irdy <= '1'; r.pci.oe_perr <= '1';
        r.noe_ad <= '0'; r.noe_ctrl <= '0'; r.noe_par <= '0';
        r.noe_req <= '0'; r.noe_frame <= '0'; r.noe_cbe <= '0';
        r.noe_irdy <= '0'; r.noe_perr <= '0';
      end if;
    end process;

    oeregs_pol0 : if oepol = 0 generate
      oeregs : process (pciclk, pcirst)
      begin
        if rising_edge (pciclk) then
          roe_ad <= rioe_ad; 
        end if;
        if (syncrst = 0) and (pcirst = '0') then -- asynch reset required
          roe_ad <= (others => '1');
        end if;
      end process;
    end generate;

    oeregs_pol1 : if oepol = 1 generate
      oeregs : process (pciclk, pcirst)
      begin
        if rising_edge (pciclk) then
          roe_ad <= rioe_ad; 
        end if;
        if (syncrst = 0) and (pcirst = '0') then -- asynch reset required
          roe_ad <= (others => '0');
        end if;
      end process;
    end generate;

    cpur : process (clk)
    begin
        if rising_edge (clk) then
            r2 <= r2in;
        end if;
    end process;

    oe0 : if oepol = 0 generate 
        pcio.inten    <= '1';
        pcio.locken   <= '1';
    end generate;

    oe1 : if oepol = 1 generate
        pcio.inten    <= '0';
        pcio.locken   <= '0';
    end generate;
    

    pcio.int      <= '1';
    pcio.lock     <= '1';

    pcio.power_state <= (others => '0');
    pcio.pme_enable <= '0';
    pcio.pme_clear <= '0';


    msttgt : if MASTER = 1 generate

        ahbmst0 : pciahbmst generic map (hindex => hmstndx, devid => GAISLER_PCIFBRG, incaddr => 1)
            port map (rst, clk, dmai, dmao, ahbmi, ahbmo);

        fifo1 : syncram_2p generic map (tech => memtech, abits => FIFO_DEPTH, dbits => FIFO_DATA_BITS, sepclk => 1)
            port map (pciclk, fifo1i.ren, fifo1i.raddr, fifo1o.rdata, clk, fifo1i.wen, fifo1i.waddr, fifo1i.wdata);

        fifo2 : syncram_2p generic map (tech => memtech, abits => FIFO_DEPTH, dbits => FIFO_DATA_BITS, sepclk => 1)
            port map (clk, fifo2i.ren, fifo2i.raddr, fifo2o.rdata, pciclk, fifo2i.wen, fifo2i.waddr, fifo2i.wdata);

        fifo3 : syncram_2p generic map (tech => memtech, abits => FIFO_DEPTH, dbits => FIFO_DATA_BITS, sepclk => 1)
            port map (pciclk, fifo3i.ren, fifo3i.raddr, fifo3o.rdata, clk, fifo3i.wen, fifo3i.waddr, fifo3i.wdata);

        fifo4 : syncram_2p generic map (tech => memtech, abits => FIFO_DEPTH, dbits => FIFO_DATA_BITS, sepclk => 1)
            port map (clk, fifo4i.ren, fifo4i.raddr, fifo4o.rdata, pciclk, fifo4i.wen, fifo4i.waddr, fifo4i.wdata);

        cbe_fifo : syncram_2p generic map (tech => 0, abits => FIFO_DEPTH, dbits => 4, sepclk => 1)
            port map (clk, cbe_fifoi.ren, cbe_fifoi.raddr, cbe_fifoo.rdata(3 downto 0), pciclk, cbe_fifoi.wen, cbe_fifoi.waddr, cbe_fifoi.wdata(3 downto 0));
        
-- pragma translate_off
        bootmsg : report_version
            generic map ("pci_mtf" & tost(hslvndx) &
                         ": 32-bit PCI/AHB bridge  rev " & tost(REVISION) &
                         ", " & tost(2**abits/2**20) & " Mbyte PCI memory BAR, " &
                         tost(2**FIFO_DEPTH) & "-word FIFOs" );
-- pragma translate_on

    end generate;

    tgtonly : if MASTER = 0 generate
        ahbmst0 : pciahbmst generic map (hindex => hmstndx, devid => GAISLER_PCIFBRG, incaddr => 1)
            port map (rst, clk, dmai, dmao, ahbmi, ahbmo);

        fifo1 : syncram_2p generic map (tech => memtech, abits => FIFO_DEPTH, dbits => FIFO_DATA_BITS, sepclk => 1)
            port map (pciclk, fifo1i.ren, fifo1i.raddr, fifo1o.rdata, clk, fifo1i.wen, fifo1i.waddr, fifo1i.wdata);

        fifo2 : syncram_2p generic map (tech => memtech, abits => FIFO_DEPTH, dbits => FIFO_DATA_BITS, sepclk => 1)
            port map (clk, fifo2i.ren, fifo2i.raddr, fifo2o.rdata, pciclk, fifo2i.wen, fifo2i.waddr, fifo2i.wdata);

        cbe_fifo : syncram_2p generic map (tech => 0, abits => FIFO_DEPTH, dbits => 4, sepclk => 1)
            port map (clk, cbe_fifoi.ren, cbe_fifoi.raddr, cbe_fifoo.rdata(3 downto 0), pciclk, cbe_fifoi.wen, cbe_fifoi.waddr, cbe_fifoi.wdata(3 downto 0));
        
-- pragma translate_off
        bootmsg : report_version
            generic map ("pci_mtf" & tost(hmstndx) &
                         ": 32-bit PCI/AHB bridge  rev, target-only, " & tost(REVISION) &
                         ", " & tost(2**abits/2**20) & " Mbyte PCI memory BAR, " &
                         tost(2**FIFO_DEPTH) & "-word FIFOs" );
-- pragma translate_on
    end generate;

end;
